home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / DevTools / eText5 / Source / Kludges.subproj / ObjectError.m < prev    next >
Encoding:
Text File  |  1994-10-29  |  8.1 KB  |  338 lines

  1. // ObjectError.m
  2. // 
  3. //  (see .h for information)
  4. //
  5. // NO WARRANTY:
  6. // ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
  7. // IS HEREBY DISCLAIMED.  IN NO EVENT WILL THE AFOREMENTIONED PARTIES BE LIABLE 
  8. // FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL 
  9. // DAMAGES ARISING OUT OF THE USE OF OR INABILITY TO USE THIS CODE.
  10.  
  11. #import "ObjectError.h"
  12. #import <appkit/Application.h>
  13. #import <appkit/nextstd.h>
  14. #import <appkit/appkit.h>
  15. #import <strings.h>
  16. #import <stdio.h>
  17. #import <sys/signal.h>
  18.  
  19. typedef struct _sig  {
  20.     int number;
  21.     BOOL isOn;
  22.     char *message;
  23. } SignalItem;
  24.  
  25. typedef struct _type  {
  26.     char encoding;
  27.     char *format;
  28.     char *name;
  29. } ObjcType;
  30.  
  31. extern SignalItem signals[];
  32. extern ObjcType encodings[];
  33.  
  34. @implementation ObjectError
  35.  
  36. static void handle_signal(int signal);
  37. static BOOL ignoreCrashes;
  38. static BOOL muddleOn;
  39.  
  40. + setup
  41. // Initialize everything and poseAs the Object class.
  42. {
  43.     [[self class] poseAs:[Object class]];
  44.     [[self class] setSignalHandler:handle_signal];
  45.     ignoreCrashes=NO;
  46.     muddleOn=NO;
  47.     return self;
  48. }
  49.  
  50. + setMuddleOn:(BOOL)flag
  51. {
  52.     muddleOn=flag;
  53.     return self;
  54. }
  55.  
  56. + setSignalHandler:(void (*)())handler
  57. {
  58.     SignalItem *cur;
  59.     
  60.     for (cur=signals; cur->number; cur++)  {
  61.         if (cur->isOn)  {
  62.             signal(cur->number, handler);
  63.         }
  64.     }
  65.     return self;
  66. }
  67.  
  68. + resumeHandlingCrashes
  69. {
  70.     [[self class] setSignalHandler:handle_signal];
  71.     ignoreCrashes=NO;
  72.     return self;
  73. }
  74.  
  75. + stopHandlingCrashes
  76. {
  77.     [[self class] setSignalHandler:(void (*)())SIG_DFL];
  78.     ignoreCrashes=YES;
  79.     return self;
  80. }
  81.  
  82. //        ASSUMPTION:  The layout of a stack frame for a method invocation is:
  83. //            fp+0 bytes:        calling frame
  84. //            fp+4 bytes:        calling pc
  85. //            fp+8 bytes:        self
  86. //            fp+12 bytes:    selector for method invoked
  87. //            fp+16 bytes:    first argument
  88. //
  89. //        ASSUMPTION: The layout of a stack frame for a function invocation is:
  90. //            fp+0 bytes:        calling frame
  91. //            fp+4 bytes:        calling pc
  92. //            fp+8 bytes:        first argument
  93. //
  94. //        Clearly these are shady assumptions, however we're already
  95. //        in the process of crashing, so what harm can be done?
  96.  
  97. #define MAX_FUNCTION_ARGS  4        // Print at most four args to a function
  98.  
  99. + printFunctionFromFP:(void *)framePointer
  100. {
  101.     char buffer[256];
  102.     char line[1024];
  103.     void *argStart;
  104.     long argNum;    // Index into arguments;
  105.     
  106.     sprintf(line, "function (");
  107.     argStart = framePointer + 8;
  108.     for (argNum=0; argNum<MAX_FUNCTION_ARGS; argNum++)  {
  109.         sprintf(buffer, "%s0x%06lx", ((argNum != 0)?", ":""), 
  110.                     *(((unsigned long *)argStart)+argNum));
  111.         strcat(line, buffer);
  112.     }
  113.     strcat(line, ")");
  114.     NXLogError("%s", line);
  115.     
  116.     return self;
  117. }
  118.  
  119. #define IS_CLASS(object)  ([object class] == object)
  120.  
  121. + printMethodFromFP:(void *)framePointer
  122. {
  123.     char buffer[256];
  124.     char line[1024];
  125.     SEL selector;
  126.     id object;
  127.     Method m;
  128.     BOOL isClassMethod;
  129.     
  130.     object = *(id *)(framePointer+8);  // receiver is 8 bytes from fp
  131.     selector = *(SEL *)(framePointer+12);  // selector is 12 bytes from fp
  132.     isClassMethod = IS_CLASS(object);
  133.     
  134.     sprintf(line, "%c[%s %s", (isClassMethod?'+':'-'), 
  135.                 object_getClassName(object), sel_getName(selector));
  136.     
  137.     m = (isClassMethod    ? class_getClassMethod([object class], selector)
  138.                         : class_getInstanceMethod([object class], selector));
  139.     
  140.     if (m)  {
  141.         void *argStart = (framePointer+8);
  142.         int argNum, numArgs, offset;
  143.         char *type;
  144.         
  145.         numArgs = method_getNumberOfArguments(m);
  146.         argNum = 2;  // Skip the first two args which are self and _cmd
  147.         while (argNum<numArgs)  {
  148.             ObjcType *cur;
  149.             
  150.             method_getArgumentInfo(m, argNum, &type, &offset);
  151.             for (cur=encodings; cur->encoding; cur++)  {
  152.                 // Find the ObjcType
  153.                 if (cur->encoding == type[0])  {
  154.                     sprintf(buffer, " :(%s)", cur->name);
  155.                     strcat(line, buffer);
  156.                     sprintf(buffer, cur->format, *(long *)(argStart+offset));
  157.                     strcat(line, buffer);
  158.                     break;
  159.                 }
  160.             }
  161.             argNum++;
  162.         }
  163.     }  else  {
  164.         strcat(line, " Unknown method");
  165.     }
  166.     strcat(line, "]");
  167.     NXLogError("%s", line);
  168.     
  169.     return self;
  170. }
  171.  
  172. #define MAX_FRAMES 50
  173.  
  174. + printBacktrace
  175. {
  176.     void *framePointer;                // pointer to current frame
  177.     unsigned int frameCount;        // counter for number of frames printed
  178.     
  179.     [self stopHandlingCrashes];        // Try to avoid re-entry problems
  180.     
  181.     // Start the frame pointer off at our frame
  182.     framePointer = ((void *) &self)-8;
  183.     frameCount=0;
  184.     
  185.     // Assume that a whole lotta frames means either (a) we're trashed or
  186.     // (b) we're in a recursive deathtrap.  In the latter case, we've
  187.     // probably got enough info to see a whole cycle.
  188.     
  189.     while (frameCount<MAX_FRAMES && framePointer)  {
  190.         // If this frame is a method call we'll have a valid 
  191.         // selector at (fp+12).
  192.         if (sel_isMapped(*(SEL *)(framePointer+12)))  {
  193.             [self printMethodFromFP:framePointer];
  194.         }  else  {
  195.             [self printFunctionFromFP:framePointer];
  196.         }
  197.         framePointer = (void *)*(long *)framePointer;  // go up one frame
  198.     }
  199.     return self;
  200. }
  201.  
  202. + dumpBacktrace:(const char *)message
  203. {
  204.     NXLogError("%s", message);
  205.     NXLogError("Here's the stack frame Backtrace:");
  206.     [self printBacktrace];
  207.     return self;
  208. }
  209.  
  210. static void handle_signal(int signal)
  211. {
  212.     const char *msg=NULL;
  213.     char buf[1024];
  214.     SignalItem *cur;
  215.     
  216.     msg = "Unrecognized signal";
  217.     for (cur = signals; cur->number; cur++)  {
  218.         if (cur->number==signal)  {
  219.             msg = cur->message;
  220.             break;
  221.         }
  222.     }
  223.     sprintf(buf, "Caught signal #%d: \"%s\"", signal, msg);
  224.     [ObjectError dumpBacktrace:buf];
  225.     if (!muddleOn)  {
  226.         exit(1);
  227.     }
  228.     [ObjectError tryToContinue];
  229. }
  230.  
  231. - error:(const char *)aString, ...
  232. {
  233.     va_list ap;
  234.     char buffer[1024];
  235.     
  236.     va_start(ap, aString);
  237.     vsprintf(buffer, aString, ap);
  238.     va_end(ap);
  239.     
  240.     if (!ignoreCrashes)  [[self class] dumpBacktrace:buffer];
  241.     if (muddleOn)
  242.     {
  243.         [[self class] tryToContinue];
  244.         return self;
  245.     }
  246.     return [super error:buffer];
  247. }
  248.  
  249. + error:(const char *)aString, ...
  250. {
  251.     va_list ap;
  252.     char buffer[1024];
  253.     
  254.     va_start(ap, aString);
  255.     vsprintf(buffer, aString, ap);
  256.     va_end(ap);
  257.     
  258.     if (!ignoreCrashes)  [[self class] dumpBacktrace:buffer];
  259.     if (muddleOn)
  260.     {
  261.         [self tryToContinue];
  262.         return self;
  263.     }
  264.     return [super error:buffer];
  265. }
  266.  
  267. + tryToContinue;
  268. {
  269.     int i;
  270.     
  271.     ignoreCrashes = NO;
  272.     NXLogError("Trying to continue...");
  273.     i = NXRunAlertPanel("Internal Error","An internal error has occurred.  Try to save work, then quit and restart the application.","Continue","Quit",NULL);
  274.     if (i == NX_ALERTALTERNATE) exit(1);
  275.     [NXApp abortModal];
  276.     return self;
  277. }
  278.  
  279. #define ON        1
  280. #define OFF        0
  281.  
  282. SignalItem signals[] = {
  283.     {SIGHUP,     OFF,     "Hangup"},
  284.     {SIGINT,     OFF,     "Interrupt"},
  285.     {SIGQUIT,     ON,     "Quit"},
  286.     {SIGILL,     ON,     "Illegal instruction"},
  287.     {SIGTRAP,     ON,     "Trace trap"},
  288.     {SIGIOT,     ON,     "IOT instruction"},
  289.     {SIGEMT,     ON,     "EMT instruction"},
  290.     {SIGFPE,     ON,     "Floating point exception"},
  291.     {SIGKILL,     OFF,     "Kill"},
  292.     {SIGBUS,     ON,     "Bus error"},
  293.     {SIGSEGV,     ON,     "Segmentation violation"},
  294.     {SIGSYS,     ON,     "Bad argument to system call"},
  295.     {SIGPIPE,     OFF,     "Write on a pipe with no one to read it"},
  296.     {SIGALRM,     OFF,     "Alarm clock"},
  297.     {SIGTERM,     OFF,     "Software termination"},
  298.     {SIGURG,     OFF,     "Urgent condition present on socket"},
  299.     {SIGSTOP,     OFF,     "Stop"},
  300.     {SIGTSTP,     OFF,     "Stop signal generated from keyboard"},
  301.     {SIGCONT,     OFF,     "Continue after stop"},
  302.     {SIGCHLD,     OFF,     "Child status changed"},
  303.     {SIGTTIN,     OFF,     "Background read attempted from control terminal"},
  304.     {SIGTTOU,     OFF,     "Background write attempted to control terminal"},
  305.     {SIGIO,     OFF,     "I/O is possible on a descriptor"},
  306.     {SIGXCPU,     OFF,     "CPU time limit is exceeded"},
  307.     {SIGXFSZ,     OFF,     "File size limit exceeded"},
  308.     {SIGVTALRM, OFF,     "Virtual timer alarm"},
  309.     {SIGPROF,     OFF,     "Profiling timer alarm"},
  310.     {SIGWINCH,     OFF,     "Window size change"},
  311.     {SIGUSR1,     OFF,     "User defined signal 1"},
  312.     {SIGUSR2,     OFF,     "User defined signal 2"},
  313.     {0},
  314. };
  315.  
  316. ObjcType encodings[] = {
  317.     {_C_ID,            "0x%06lx",        "id"},
  318.     {_C_CLASS,        "0x%06lx",        "Class"},
  319.     {_C_SEL,        "%s",            "SEL"},
  320.     {_C_CHR,        "%c",            "char"},
  321.     {_C_UCHR,        "%c",            "unsigned char"},
  322.     {_C_SHT,        "%s",            "short"},
  323.     {_C_USHT,        "%c",            "unsigned short"},
  324.     {_C_INT,        "%d",            "int"},
  325.     {_C_UINT,        "%d",            "unsigned int"},
  326.     {_C_LNG,        "%l",            "long"},
  327.     {_C_ULNG,        "%l",            "unsigned long"},
  328.     {_C_FLT,        "%f",            "float"},
  329.     {_C_DBL,        "%f",            "double"},
  330.     {_C_VOID,        "0x%06lx",        "void"},
  331.     {_C_PTR,        "0x%06lx",        "ptr"},
  332.     {_C_CHARPTR,    "%s",            "char *"},
  333.     {_C_STRUCT_B,    "%x",            "struct"},
  334.     {0,                "0x%06lx",        "unknown type"},
  335. };
  336.  
  337. @end
  338.